package com.cs51.seam;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.sun.org.apache.xml.internal.security.utils.Base64;


/**
 * Servlet implementation class Main
 */
public class Main extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		System.out.println("has get request");
		doPost(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		//taken from: http://stackoverflow.com/questions/2422468/how-to-upload-files-to-server-using-jsp-servlet/2424824#2424824

	    try {
	    	//set up the map of variables
			HashMap<String, String> requestMap = new HashMap<String, String>();
			//have a place for the image
			BufferedImage img = null;
			
			//go through the request
	        List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
	        System.out.println("Going through parameters");
	        for (FileItem item : items) {
	        	//if just a regular old field, print it out and put it in the requestMap
	            if (item.isFormField()) {
	            	System.out.println("Key: " + item.getFieldName() + "    Value: " + item.getString());
	            	requestMap.put(item.getFieldName(), item.getString());
	            }	
	            //otherwise, set our image
	            else
	            	img = Utils.getImage(item.getInputStream());	        
	        }
			writeResponse(response, sendResults(img, requestMap));
			
	    } catch (FileUploadException e) {
	        throw new ServletException("Cannot parse multipart request.", e);
	    }
	}

	/**
	 * given the image to be parsed and the request with parameters, returns
	 * file array for images
	 * 
	 * @param img the image paremeter
	 * @param request the request with remaining parameters
	 * @return returns file array contain necessary images
	 * @throws IOException 
	 */
	public static File[] sendResults(BufferedImage img, HashMap<String, String> options) throws IOException {		
		//check if necessary arguments are present
		if (img == null)
			throw new IllegalArgumentException("Program requires argument for image");
		
		//TODO change parameters to appropriate field		
		Resizer resizer = new Resizer(img,
			SeamConstants.SEAM_DEFAULT_MAX_SCORE,
			((options.containsKey("width")) ? 
				Integer.parseInt(options.get("width")) : 
				(int) ((SeamConstants.SEAM_DEFAULT_MAX_HORZ_PROPORTION) * img.getWidth())), 
			((options.containsKey("height")) ? 
				Integer.parseInt(options.get("height")) :
				(int) ((SeamConstants.SEAM_DEFAULT_MAX_VERT_PROPORTION) * img.getHeight())),
			SeamConstants.DEFAULT_ENERGY_METHOD,
			(options.get("seamEnlarge") == "Yes") ? true : false);
		
		return new File[] {
			Utils.imageToTempFile(resizer.getSeamCarve().getEnergyGetter().getImage()),
			Utils.imageToTempFile(resizer.getSeamCarve().getSeamImage()),
			Utils.imageToTempFile(resizer.getFinalImage())
		};
	}

	/**
	 * Encodes the byte array into base64 string
	 * 
	 * @param imageByteArray
	 *            byte array
	 * @return String a {@link java.lang.String}
	 * @throws IOException
	 */
	public static String encodeImage(BufferedImage img, String type)
			throws IOException {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		Utils.writeImage(img, type, baos);
		baos.flush();
		byte[] imageByteArray = baos.toByteArray();
		return Base64.encode(imageByteArray);
	}

	/**
	 * Used to write array of files in to response object. objects are converted
	 * into JSON objects
	 * 
	 * @param response
	 *            the servlet response
	 * @param files
	 *            the files to write to the response
	 * @param img
	 * @throws ServletException
	 * @throws IOException
	 */
	public static void writeResponse(HttpServletResponse response, File[] files)
			throws ServletException, IOException {

		StringBuffer jsonString = new StringBuffer();
		BufferedImage imgage;

		ServletOutputStream stream = null;
		try {
			for (int i = 0; i < files.length; i++) {
				imgage = Utils.getImage(files[i]);
				jsonString.append(encodeImage(imgage, "png")).append(",");
			}
			/*
			 * Cache control property is set to avoid OutputStream Already
			 * obtained error...
			 */
			response.setHeader("Cache-Control", "no-store");
			response.setHeader("Pragma", "no-cache");
			response.setDateHeader("Expires", 0);
			/*
			 * JSON data in response...
			 */
			response.setContentType("application/json; charset=UTF-8");
			response.setContentLength(jsonString.length());
			response.getWriter().write(jsonString.toString());
		} catch (IOException ioe) {
			ioe.printStackTrace();
			throw new ServletException(ioe.getMessage());
		} finally {
			if (stream != null) {
				stream.close();
			}
		}

	}
}
